home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1993 David Engel
- *
- * This program may be used for any purpose as long as this
- * copyright notice is kept.
- */
-
- #include <stdio.h>
- #include <string.h>
- #include <stdarg.h>
- #include <getopt.h>
- #include <unistd.h>
- #include <errno.h>
- #include <a.out.h>
- #include <sys/stat.h>
-
- #define VERSION "1.0 (8/16/93)"
-
- char *prog = "chlib";
-
- volatile void error(char *fmt, ...)
- {
- va_list ap;
-
- fprintf(stderr, "%s: ", prog);
-
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
-
- fprintf(stderr, "\n");
-
- exit(1);
- }
-
- /* read relevant info about a shared library. */
-
- int libinfo(int must, char *name, unsigned *addr, unsigned *vers,
- struct stat *stbuf)
- {
- FILE *file;
- struct exec exec;
-
- /* see if we can stat it */
- if (stat(name, stbuf))
- {
- /* if must exist flag is set, it's an error */
- if (must)
- error("can't stat %s (%s)", name, strerror(errno));
- else
- return 0;
- }
-
- /* try to open it */
- if ((file = fopen(name, "rb")) == NULL)
- error("can't open %s (%s)", name, strerror(errno));
-
- /* and read the exec header */
- if (fread(&exec, sizeof exec, 1, file) != 1)
- error("can't read exec header from %s", name);
-
- /* shared libs must be ZMAGIC */
- if (N_MAGIC(exec) != ZMAGIC || !exec.a_entry)
- error("%s is not a shared library", name);
-
- *addr = exec.a_entry;
-
- /* now seek to where the version number */
- if (fseek(file, N_TXTOFF(exec), SEEK_SET))
- error("can't seek to version in %s", name);
-
- /* and try to read the version number */
- if (fread(vers, sizeof *vers, 1, file) != 1)
- error("can't read version number from %s", name);
-
- /* we're done with the file */
- fclose(file);
-
- return 1;
- }
-
- int main(int argc, char **argv)
- {
- int c;
- int force = 0;
- char *newlib;
- char *linkdir;
- char *cp, *cp2;
- char linkname[1024];
- unsigned newaddr, oldaddr;
- unsigned newvers, oldvers;
- struct stat newstat, oldstat;
- struct stat linkstat;
-
- prog = argv[0];
- opterr = 0;
-
- /* parse command-line options */
- while ((c = getopt(argc, argv, "vf")) != EOF)
- switch (c)
- {
- case 'v':
- printf("%s: version %s\n", argv[0], VERSION);
- exit(0);
- case 'f':
- force = 1;
- break;
- default:
- error("invalid option -%c", optopt);
- }
-
- /* must be either one or two args left */
- if (argc - optind < 1 || argc - optind > 2)
- {
- fprintf(stderr, "usage: %s [-vf] newlib [linkdir]\n", argv[0]);
- exit(1);
- }
-
- /* pick off newlib argument */
- newlib = argv[optind];
-
- /* pick off linkdir argumnet or use default */
- if (argc - optind > 1)
- {
- linkdir = argv[optind+1];
-
- /* strip trailing slashes from linkdir */
- for (cp = linkdir+strlen(linkdir)-1;
- cp > linkdir && *cp == '/'; cp--)
- ;
- cp[1] = '\0';
- }
- else
- linkdir = "/lib";
-
- /* make sure linkdir is a directory */
- if (stat(linkdir, &linkstat) || !S_ISDIR(linkstat.st_mode))
- error("%s is not a directory", linkdir);
-
- /* check if newlib is a valid shared library name */
- cp = strrchr(newlib, '/');
- if (cp)
- cp++;
- else
- cp = newlib;
- cp2 = strstr(cp, ".so.");
- if (cp2)
- cp2 = strchr(cp2 + 4, '.');
- if (!cp2)
- error("%s is not a shared library name", newlib);
-
- /* build the shared library link name */
- sprintf(linkname, "%s/", linkdir);
- strncat(linkname, cp, cp2 - cp);
-
- /* check for for relative newlib and absolute linkdir */
- if (*newlib != '/' && *linkdir == '/')
- {
- if (strcmp(linkdir, getcwd(NULL, 0)) != 0)
- error("current directory is not %s", linkdir);
- }
-
- /* read info about the new shared library */
- libinfo(1, newlib, &newaddr, &newvers, &newstat);
-
- /* try to read info about any existing library */
- if (libinfo(0, linkname, &oldaddr, &oldvers, &oldstat))
- {
- /* see if the link is already set to newlib */
- if (newstat.st_dev == oldstat.st_dev &&
- newstat.st_ino == oldstat.st_ino)
- error("%s already points to %s", linkname, newlib);
-
- /* make sure the load addresses match */
- if (newaddr != oldaddr)
- error("load address for %s (0x%x) does not match\n"
- "\tthat of current %s (0x%x)", newlib, newaddr,
- linkname, oldaddr);
-
- /* make sure the major version numbers match */
- if ((0xffff0000 & newvers) != (0xffff0000 & oldvers))
- error("major version for %s (%d) does not match\n"
- "\tthat of current %s (%d)", newlib, newvers >> 16,
- linkname, oldvers >> 16);
-
- /* make sure the new minor version number is greater */
- if (!force && (0x0000ffff & newvers) <= (0x0000ffff & oldvers))
- error("minor version of %s (%d) is not greater than\n"
- "\tthat of current %s (%d)", newlib, newvers & 0xffff,
- linkname, oldvers & 0xffff);
- }
-
- /* remove any existing link */
- if (!lstat(linkname, &oldstat) && remove(linkname))
- error("can't unlink %s (%s)", linkname, strerror(errno));
-
- /* (re)create the new link to newlib */
- if (symlink(newlib, linkname))
- error("can't create link to %s (%s)", newlib, strerror(errno));
-
- /* that's all folks */
- exit(0);
- }
-